<?php
/**
 * TinyCatPHP 极简、快速、创新、易用、高性能的PHP应用开发框架
 * User: CnTaiGe <hst042@163.com>
 * Date: 2017/11/19
 */

namespace TinyCatPHP\libs\handler;

use TinyCatPHP\exception\SysException;
use TinyCatPHP\libs\utils\Log;
use TinyCatPHP\libs\utils\Running;

class Response
{
    protected static $headers = [];

    /**
     * 设置响应头
     * @param $field
     * @param $content
     */
    public static function header($field, $content)
    {
        self::$headers[$field] = $content;
    }

    /**
     * 页面输出类型
     * @param string $contentType 输出类型
     * @param string $charset 输出编码
     */
    public static function contentType($contentType, $charset = 'UTF-8')
    {
        self::$headers['Content-Type'] = $contentType . '; charset=' . $charset;
    }

    public static function responseCode($code)
    {
        http_response_code($code);
    }

    /**
     * 根据action响应请求
     * @param $requestUri
     * @throws SysException
     */
    public static function moduleAction($requestUri)
    {
        $beforeFn = null;//前置方法
        $afterFn = null;//后置方法
        $clsMth = explode('/', trim($requestUri, '/'));
        $cls = '';
        $mth = '';
        if (count($clsMth) === 3) {
            $cls = $clsMth[0] . '\\controller\\' . $clsMth[1];
            $mth = $clsMth[2];
        } else if (count($clsMth) === 2) {
            $cls = 'controller\\' . $clsMth[0];
            $mth = $clsMth[1];
        }
        Request::setPathsInfo([
            'route' => $requestUri,
            'module' => $clsMth[0],
            'action' => isset($clsMth[1]) ? $clsMth[1] : null,
            'method' => isset($clsMth[2]) ? $clsMth[2] : null
        ]);
        if (class_exists($cls)) {
            $cls = new  $cls();
            if (method_exists($cls, $mth)) {
                if (!is_callable([$cls, $mth])) throw new SysException('404 Not Found', -1);
                $mre = new \ReflectionClass($cls);
                $mreMthDoc = $mre->getMethod($mth)->getDocComment();
                //解析注解
                $pregContents = [];
                preg_match_all('/@.*/', $mreMthDoc, $pregContents);
                if (count($pregContents) !== 0) {
                    foreach ($pregContents[0] as $extra) {
                        $extraFn = explode('=', $extra);
                        if (trim($extraFn[0]) === '@before' && !empty($extraFn[1]))
                            $beforeFn = trim($extraFn[1]);
                        if (trim($extraFn[0]) === '@after' && !empty($extraFn[1]))
                            $afterFn = trim($extraFn[1]);
                    }
                }
                Interceptor::instance()->runAction();
                //执行前置
                if (function_exists($beforeFn))
                    call_user_func($beforeFn);
                self::showInfoView(call_user_func([$cls, $mth]));
                //执行后置方法
                if (function_exists($afterFn))
                    call_user_func($afterFn);
                return;
            } else
                throw new SysException('404 Not Found', -1);
        } else
            throw new SysException('404 Not Found', -1);
    }

    /**
     * 路由定义响应
     * @param $routers
     * @param $requestUri
     * @throws SysException
     */
    public static function routers($routers, $requestUri)
    {
        $beforeFn = null;//前置方法
        $afterFn = null;//后置方法
        if ($routers[$requestUri]['extra_info']) {
            foreach ($routers[$requestUri]['extra_info'] as $extra) {
                $extraFn = explode('=', $extra);
                if (trim($extraFn[0]) === '@before' && !empty($extraFn[1]))
                    $beforeFn = trim($extraFn[1]);
                if (trim($extraFn[0]) === '@after' && !empty($extraFn[1]))
                    $afterFn = trim($extraFn[1]);
            }
        }
        //调用相关方法
        $route = $routers[$requestUri];
        Request::setPathsInfo([
            'route' => $requestUri,
            'action' => $route['class'],
            'method' => $route['method']
        ]);
        if (class_exists($route['class'])) {
            $cls = new $route['class']();
            if (method_exists($cls, $route['method'])) {
                if (!is_callable([$cls, $route['method']])) throw new SysException('404 Not Found', -1);
                Interceptor::instance()->runAction();
                if ($beforeFn !== null)
                    //执行前置方法
                    if (function_exists($beforeFn))
                        call_user_func($beforeFn);
                    else
                        throw  new SysException('not found ' . $beforeFn);
                self::showInfoView(call_user_func([$cls, $route['method']]));
                if ($afterFn !== null)
                    //执行后置方法
                    if (function_exists($afterFn))
                        call_user_func($afterFn);
                    else
                        throw  new SysException('not found ' . $afterFn);
            } else {
                throw new SysException('404 Not Found', -1);
            }
        } else {
            throw new SysException('404 Not Found', -1);
        }
    }

    /**
     * 输出页面信息
     * @param array $info
     */
    protected static function showInfoView($info)
    {
        self::endOut();
        if (is_array($info) && isset($info['type'])) {
            switch ($info['type']) {
                case 'file':
                    extract($info['data'], EXTR_SKIP);
                    include $info['file'];
                    break;
                default:
                    echo $info['content'];
            }
        } elseif (!is_null($info)) {
            if (gettype($info) === 'array' || gettype($info) === 'object') {
                echo json_encode($info, JSON_UNESCAPED_UNICODE);
            } else {
                echo $info;
            }
        }
        $logicMem = Running::tagMemory('service_logic');
        $logicTime = Running::tagTime('service_logic');
        Log::record('info', '业务逻辑执行完成 [执行时间: ' . $logicTime . 's] [使用内存:' . $logicMem . ']');
    }

    /**
     * 输出头部信息
     */
    public static function endOut()
    {
        if (headers_sent()) return;
        foreach (self::$headers as $k => $v) {
            header($k . ': ' . $v);
        }
    }
}